home *** CD-ROM | disk | FTP | other *** search
- /*
- ReadMatLabFile.c - load/save a matrix from/to a MatLab file.
-
- Note: these functions are indepedent of MatLab itself. You can use these
- functions from with a stand-alone C application, or from within a MATLAB file,
- i.e. a MatLab code resource.
-
- This example loads two matrices from a MatLab file:
-
- FILE *f;
- char name[64];
- long rows,cols;
- double *xr,*xi;
- short *mr,*mi;
- int error;
- f = fopen("foo.mat","rb");
- error=LoadMatDoubles(f,name,&rows,&cols,&xr,&xi);// Read 8-byte doubles into doubles
- error=LoadMatShorts(f,name,&rows,&cols,&mr,&mi); // Read 8-byte doubles into shorts
- fclose(f);
- free(xr);
- free(xi);
- free(mr);
- free(mi);
-
- This example saves four matrices to disk, creating a MatLab file:
-
- FILE *fp;
- double xyz[1000],ar[1000],ai[1000];
- short m[100],n[100];
- fp = fopen("bar.mat","wb");
- SetFileInfo("bar.mat",'MATW','MATL');
- error=SaveMatDoubles(fp,"xyz",2,3,xyz,NULL); // real
- error=SaveMatShorts(fp,"m",2,3,m,NULL); // real
- error=SaveMatDoubles(fp,"a",5,5,ar,ai); // complex
- error=SaveMatShorts(fp,"mc",2,3,m,n); // complex
- fclose(fp);
-
- The LoadMatXXX and SaveMatXXX routines return 0 if successful and 1 if they
- fail. They can be called repeatedly until they fail (e.g. end of file is
- reached). The two array pointers will be NULL after calling LoadMatXXX unless
- they are loaded. The second (imaginary) pointer will be NULL unless the matrix
- was complex. Similarly, when you call SaveMatXXX you indicate a real matrix by
- supplying a NULL second pointer.
-
- PROTOTYPES:
- int LoadMatDoubles(FILE *f,char *name,long *rows,long *cols
- ,double **real,double **imag); // read 8-byte DOUBLES into doubles
- int LoadMatShorts(FILE *f,char *name,long *rows,long *cols
- ,short **real,short **imag); // read 8-byte DOUBLES into shorts
- int SaveMatDoubles(FILE *f,char *name,long rows,long cols
- ,double *real,double *imag); // write doubles as 8-byte DOUBLES
- int SaveMatShorts(FILE *f,char *name,long rows,long cols
- ,short *real,short *imag); // write shorts as shorts
-
- There is a slight asymmetry here that you should be aware of. SaveMatShorts()
- produces a (compact) MatLab file made up of shorts, but the LoadMatShorts() will
- only read a (big) MatLab file made up of 8-byte doubles. So you won't always be
- able to read from C the file you wrote from C. The reason for this is that while
- the MatLab "Load" command supports all the MatLab file formats, the MatLab
- "Save" command has no provision for specifying (binary) file formats and thus
- always uses format type 0, 8-byte short doubles, so I didn't bother to implement
- any routines to read any other format.
-
- HISTORY:
- 11-3-86 J.N. Little wrote loadmat.c and savemat.c
-
- [14-Feb-91] jmb -- Added support for MPW C 3.x and THINK C.
-
- 1/4/93 dgp Renamed MatLab.c. DOUBLE is now used soley within the
- new WriteXXX and ReadXXX subroutines. C users now only deal with double and short
- arrays; necessary conversions are done behind the scenes. double is faster and
- more convenient for Macintosh programming than the 8-byte short double used in
- the MatLab files. Added support for file format 3: signed short ints. Omitted
- the imagf flag since it's redundant. Omitted the type argument by supplying
- several user-callable front ends, each tailored to a particular number type.
-
- 2/93 dgp Renamed ReadMatLabFile.c
- */
- #include "VideoToolbox.h"
- #include <assert.h>
-
- double *ReadDoubles(FILE *f,long elements,char *name);
- short *ReadDoublesIntoShorts(FILE *f,long elements,char *name);
- int WriteDoubles(FILE *f,long elements,char *name,double *d);
- int WriteShorts(FILE *f,long elements,char *name,short *d);
- int LoadMat(FILE *f,char *name,long *rows,long *cols
- ,void **real,void **imag,long *fileType,long desiredNumberType);
- int SaveMat(FILE *f,char *name,long rows,long cols,void *real,void *imag,long type);
-
- typedef struct {
- long type; /* type */
- long rows; /* row dimension */
- long cols; /* column dimension */
- long imagf; /* flag indicating imag part */
- long namlen; /* name length (including NULL) */
- } Fmatrix;
-
- /* From cmex.h */
- // MatLab files with number format 0 use 8-byte floating point numbers, which
- // we'll call DOUBLE.
- #undef DOUBLE
- #ifdef THINK_C
- #define DOUBLE short double
- #else
- #define DOUBLE double
- #endif
-
-
- LoadMatDoubles(FILE *f,char *name,long *rows,long *cols
- ,double **real,double **imag)
- {
- long fileType,desiredNumberType=0;
-
- return LoadMat(f,name,rows,cols,(void **)real,(void **)imag
- ,&fileType,desiredNumberType);
- }
-
- LoadMatShorts(FILE *f,char *name,long *rows,long *cols
- ,short **real,short **imag)
- {
- long fileType,desiredNumberType=3;
-
- return LoadMat(f,name,rows,cols,(void **)real,(void **)imag
- ,&fileType,desiredNumberType);
- }
-
- int SaveMatDoubles(FILE *f,char *name,long rows,long cols,double *real,double *imag)
- {
- return SaveMat(f,name,rows,cols,real,imag,0);
- }
-
- int SaveMatShorts(FILE *f,char *name,long rows,long cols,short *real,short *imag)
- {
- return SaveMat(f,name,rows,cols,real,imag,30);
- }
-
- LoadMat(FILE *f,char *name,long *rows,long *cols
- ,void **real,void **imag,long *fileType,long desiredNumberType)
- {
- Fmatrix x;
- long elements,namlen,imagf,numberFormat;
-
- *real=*imag=NULL;
-
- // Get Fmatrix structure from file
- if (fread((char *)&x,sizeof(Fmatrix),1,f) != 1) return 1;
- *fileType = x.type;
- *rows = x.rows;
- *cols = x.cols;
- namlen = x.namlen;
- elements = x.rows * x.cols;
-
- if(x.type/1000!=1)return 1; // not Macintosh-compatible binary format
- if(x.type/100%10!=0)return 1; // transposed
- numberFormat=x.type/10%10;
- if(numberFormat!=0)return 1; // not 8-byte doubles
-
- // Get matrix name from file
- if (fread(name,sizeof(char),namlen,f) != namlen) return 1;
-
- // Get Real part of matrix from file
- switch(desiredNumberType){
- case 0:
- *real=ReadDoubles(f,elements,name);
- break;
- case 3:
- *real=ReadDoublesIntoShorts(f,elements,name);
- break;
- default:
- real=NULL;
- }
- if(*real==NULL)return 1;
-
- // Get Imag part of matrix from file, if it exists
- if (x.imagf) {
- switch(desiredNumberType){
- case 0:
- *imag=ReadDoubles(f,elements,name);
- break;
- case 3:
- *imag=ReadDoublesIntoShorts(f,elements,name);
- break;
- }
- if(*imag==NULL){
- free(*real);
- *real=NULL;
- return 1;
- }
- }
- return 0;
- }
-
- int SaveMat(FILE *f,char *name,long rows,long cols,void *real,void *imag,long type)
- {
- Fmatrix x;
- long elements;
- int error;
- int fileFormat;
-
- type%=100; // not transposed
- type+=1000; // indicate Macintosh-compatible binary format
- x.type = type;
- x.rows = rows;
- x.cols = cols;
- if(imag==NULL)x.imagf=0;
- else x.imagf=1;
- x.namlen = strlen(name) + 1;
- elements = x.rows * x.cols;
-
- if(x.type/1000!=1)return 1; // not Macintosh-compatible binary format
- if(x.type/100%10!=0)return 1; // transposed
- fileFormat=x.type/10%10;
- if(fileFormat!=0 && fileFormat!=3)return 1; // neither 8-byte double, nor short
-
- fwrite(&x,sizeof(Fmatrix),1,f);
- fwrite(name,sizeof(char),(long)x.namlen,f);
- switch(fileFormat){
- case 0:
- error=WriteDoubles(f,elements,name,real);
- break;
- case 3:
- error=WriteShorts(f,elements,name,real);
- break;
- default:
- error=1;
- }
- if(error)return 1;
- if (imag!=NULL) {
- switch(fileFormat){
- case 0:
- error=WriteDoubles(f,elements,name,imag);
- break;
- case 3:
- error=WriteShorts(f,elements,name,imag);
- break;
- default:
- error=1;
- }
- if(error)return 1;
- }
- return 0;
- }
-
- // Reads DOUBLES (8-byte short doubles) into doubles
- double *ReadDoubles(FILE *f,long elements,char *name)
- {
- DOUBLE *D;
- double *d;
- long i,n,j;
- const dSize=2048/sizeof(DOUBLE); // Can be whatever you want. Bigger is faster.
-
- assert(sizeof(DOUBLE)==8);
- D=(DOUBLE *)malloc(dSize*sizeof(DOUBLE));
- if(D==NULL){
- printf("\nError: not enough room for buffer\n");
- return NULL;
- }
- if (!(d = (double *)malloc(elements*sizeof(*d)))) {
- printf("\nError: Variable %s too big to load\n",name);
- return NULL;
- }
- for(i=0;i<elements;){
- if(dSize<elements-i)n=dSize;
- else n=elements-i;
- if(fread(D,sizeof(DOUBLE),n,f) != n) {
- free(d);
- free(D);
- return NULL;
- }
- for(j=0;j<n;j++)d[i++]=D[j]; // convert DOUBLE to double
- }
- free(D);
- return d;
- }
-
- // Reads DOUBLES (8-byte short doubles) into shorts
- short *ReadDoublesIntoShorts(FILE *f,long elements,char *name)
- {
- DOUBLE *D;
- short *d;
- long i,n,j;
- const dSize=2048/sizeof(DOUBLE); // Can be whatever you want. Bigger is faster.
-
- assert(sizeof(DOUBLE)==8);
- D=(DOUBLE *)malloc(dSize*sizeof(DOUBLE));
- if(D==NULL){
- printf("\nError: not enough room for buffer\n");
- return NULL;
- }
- if (!(d = (short *)malloc(elements*sizeof(*d)))) {
- printf("\nError: Variable %s too big to load\n",name);
- return NULL;
- }
- for(i=0;i<elements;){
- if(dSize<elements-i)n=dSize;
- else n=elements-i;
- if(fread(D,sizeof(DOUBLE),n,f) != n) {
- free(d);
- free(D);
- return NULL;
- }
- for(j=0;j<n;j++)d[i++]=D[j]; // convert DOUBLE to short
- }
- free(D);
- return d;
- }
-
- // Writes doubles as DOUBLES (8-byte short doubles)
- int WriteDoubles(FILE *f,long elements,char *name,double *d)
- {
- DOUBLE *D;
- long i,n,j;
- const dSize=2048/sizeof(DOUBLE); // Can be whatever you want. Bigger is faster.
-
- assert(sizeof(DOUBLE)==8);
- if (d==NULL) return 1;
- D=(DOUBLE *)malloc(dSize*sizeof(DOUBLE));
- if(D==NULL){
- printf("\nError: not enough room for buffer\n");
- return 1;
- }
- for(i=0;i<elements;){
- if(dSize<elements-i)n=dSize;
- else n=elements-i;
- for(j=0;j<n;j++)D[j]=d[i++]; // convert double to DOUBLE
- if(fwrite(D,sizeof(DOUBLE),n,f) != n) {
- free(D);
- return 1;
- }
- }
- free(D);
- return 0;
- }
-
- // Writes shorts as shorts
- int WriteShorts(FILE *f,long elements,char *name,short *d)
- {
- assert(sizeof(short)==2);
- if (d==NULL) return 1;
- if(fwrite(d,sizeof(short),elements,f) != elements) return 1;
- return 0;
- }
-